package com.dbflow5.transaction;

import com.dbflow5.config.FlowLog;

import java.util.concurrent.LinkedBlockingQueue;

/**
 * Description: Handles concurrent requests to the database and puts them in FIFO order based on a
 * [LinkedBlockingQueue]. As requests come in, they're placed in order and ran one at a time
 * until the queue becomes empty.
 */
public class DefaultTransactionQueue extends Thread implements ITransactionQueue {

    private final LinkedBlockingQueue<Transaction<?>> queue = new LinkedBlockingQueue<>();

    private boolean isQuitting = false;

    public DefaultTransactionQueue(String name){
        super(name);
    }

    @Override
    public void run() {
        //Looper.prepare();
        //Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
        Transaction<?> transaction;
        while (true) {
            try {
                transaction = queue.take();
            } catch (InterruptedException e) {
                synchronized(this) {
                    if (isQuitting) {
                        synchronized(queue) {
                            queue.clear();
                        }
                        return;
                    }
                }
                continue;
            }

            synchronized(this) {
                if (!isQuitting) {
                    transaction.executeSync();
                }
            }
        }
    }

    @Override
    public void add(Transaction<?> transaction) {
        synchronized(queue) {
            if (!queue.contains(transaction)) {
                queue.add(transaction);
            }
        }
    }

    /**
     * Cancels the specified request.
     *
     * @param transaction transaction
     */
    @Override
    public void cancel(Transaction<?> transaction) {
        synchronized(queue) {
            if (queue.contains(transaction)) {
                queue.remove(transaction);
            }
        }
    }

    @Override
    public void startIfNotAlive() {
        synchronized(this) {
            if (!isAlive()) {
                try {
                    start();
                } catch (IllegalThreadStateException i) {
                    // log if failure from thread is still alive.
                    FlowLog.log(FlowLog.Level.E, i.getMessage());
                }

            }
        }
    }

    @Override
    public void cancel(String name) {
        synchronized(queue) {
            queue.removeIf(next -> next.name != null && next.name.equals(name));
        }
    }

    /**
     * Quits this process
     */
    @Override
    public void quit() {
        synchronized(this) {
            isQuitting = true;
        }
        interrupt();
    }
}

